package Threading2;
// synchronized 的使用：可以直接使用代码块的形式来给某一段代码加锁

// synchronized 如果直接修饰方法，此时就相当于 以 this 为锁对象
// synchronized 如果修饰的是静态方法，此时就是给类对象加锁
class Counter {
    private int count = 0;
    public void add() {
        synchronized (this) {
            count++;
        }
    }

    synchronized public void test() {
        // 这种就相当于以this为锁对象，和上述写法是一样的
    }

    synchronized public static void test2() {
        // 这种就相当于下边代码的写法
    }
    public static void test3() {
        synchronized (Counter.class) {

        }
    }

    public int get() {
        return count;
    }
}

public class ThreadDemo8 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        // 创建两个线程，两个线程分别对这个 counter 自增 5w 次，结果应该是10w
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();

        // 最后获得这个自增之后的结果
        t1.join();
        t2.join();
        System.out.println(counter.get());
    }

    // 这个自增操作看起来是一步操作，但是其实是三个CPU指令，因为此时线程的调度是无序的，所以就有可能出现覆盖结果的情况
    // 所以此时这俩线程就是不安全的
}
